package net.sureon.job.reminder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sureon.app.AppContext;
import net.sureon.app.UserSession;
import net.sureon.biz.CompanyBO;
import net.sureon.biz.CompanyConfigBO;
import net.sureon.biz.CompanyMgr;
import net.sureon.biz.ReminderMgr;
import net.sureon.biz.TitaonMailHelper;
import net.sureon.biz.UserBO;
import net.sureon.biz.UserMgr;
import net.sureon.common.I18nSupport;
import net.sureon.common.mail.MailData;
import net.sureon.common.mail.MailProcessor;
import net.sureon.dao.DailyTimingReminder;
import net.sureon.dao.ToBeApproveReminder;
import net.sureon.job.SimpleJob;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DailyTimingAndApplicationReminder implements SimpleJob {
	private static final Log logger = LogFactory
			.getLog(DailyTimingAndApplicationReminder.class);
	private static final int ONE_DAY_IN_MS = 1000 * 3600 * 24;
	private UserMgr userMgr;
	private ReminderMgr reminderMgr;
	private CompanyMgr companyMgr;

	/**
	 * @return the userMgr
	 */
	public UserMgr getUserMgr() {
		return userMgr;
	}

	/**
	 * @param userMgr
	 *            the userMgr to set
	 */
	public void setUserMgr(UserMgr userMgr) {
		this.userMgr = userMgr;
	}

	/**
	 * @return the reminderMgr
	 */
	public ReminderMgr getReminderMgr() {
		return reminderMgr;
	}

	/**
	 * @return the companyMgr
	 */
	public CompanyMgr getCompanyMgr() {
		return companyMgr;
	}

	/**
	 * @param companyMgr
	 *            the companyMgr to set
	 */
	public void setCompanyMgr(CompanyMgr companyMgr) {
		this.companyMgr = companyMgr;
	}

	/**
	 * @param reminderMgr
	 *            the reminderMgr to set
	 */
	public void setReminderMgr(ReminderMgr reminderMgr) {
		this.reminderMgr = reminderMgr;
	}

	public void execute() throws Exception {
		List<CompanyBO> companies = companyMgr.getAllCompanies();
		long companyID;
		CompanyConfigBO cConfig;
		for (CompanyBO company : companies) {
			Map<Long, UserReminder> reminderEntires = new HashMap<Long, UserReminder>();
			companyID = company.getCompanyID();
			cConfig = companyMgr.getCompanyConfig(companyID);
			List<DailyTimingReminder> dailyTimingReminders = reminderMgr
					.getDailyTimingReminderList(companyID, cConfig
							.getDailyTimingReminderInterval());
			for (DailyTimingReminder item : dailyTimingReminders) {
				try {
					UserReminder ur = reminderEntires.get(item.getUserID());
					if (ur == null) {
						ur = new UserReminder();
						ur.theUser = userMgr.getUser(companyID, item
								.getUserID());
						ur.dtReminder = item;
						reminderEntires.put(item.getUserID(), ur);
					}
				} catch (Exception e1) {
					logger.error("process dailyTiming item failed, userID="
							+ item.getUserID() + ", companyID="
							+ item.getCompanyID(), e1);
				}
			}

			List<ToBeApproveReminder> dailyTimingApprovals = reminderMgr
					.getToBeRemindedDailyTimingApproval(companyID, cConfig.getDailyTimingReminderApproveInterval());
			addToReminderItems(companyID, dailyTimingApprovals, reminderEntires);

			List<ToBeApproveReminder> applications = reminderMgr
					.getToBeRemindedApplications(companyID, cConfig
							.getAutoApproveDays());
			addToReminderItems(companyID, applications, reminderEntires);

			sendCompanyReminder(companyID, reminderEntires);
		}

	}

	private void addToReminderItems(long companyID,
			List<ToBeApproveReminder> applications,
			Map<Long, UserReminder> reminderEntires) {
		for (ToBeApproveReminder app : applications) {
			try {
				UserBO user = userMgr.getUser(companyID, app.getApplierID());
				long reminderUserID = user.getUserVO().getSuperiorID();
				if(reminderUserID <= 0){
					continue;
				}
				UserReminder ur = reminderEntires.get(reminderUserID);
				if (ur == null) {
					ur = new UserReminder();
					ur.theUser = userMgr.getUser(companyID, reminderUserID);
					reminderEntires.put(reminderUserID, ur);
				}
				ur.add(app, user);
			} catch (Exception e2) {
				logger.error("process Application item failed: type="
						+ app.getType() + ", id=" + app.getTheID()
						+ ", companyID:" + app.getCompanyID(), e2);
			}
		}
	}

	private void sendCompanyReminder(long companyID,
			Map<Long, UserReminder> entries) {
		if (logger.isDebugEnabled()) {
			logger.debug("start to process sending reminder for company:"
					+ companyID);
		}
		Map.Entry<Long, UserReminder> entry;
		Iterator<Map.Entry<Long, UserReminder>> itr = entries.entrySet()
				.iterator();
		while (itr.hasNext()) {
			entry = itr.next();
			if (logger.isDebugEnabled()) {
				logger.debug("start to process sending reminder for user:"
						+ entry.getKey());
			}
			sendUserReminder(companyID, entry.getKey(), entry.getValue());
			if (logger.isDebugEnabled()) {
				logger.debug("end to process sending reminder for user:"
						+ entry.getKey());
			}
		}
		if (logger.isDebugEnabled()) {
			logger.debug("end to process sending reminder for company:"
					+ companyID);
		}
	}

	private void sendUserReminder(long companyID, long userID,
			UserReminder reminder) {
		try {
			UserSession sess = AppContext.getCurrentUserSession();
			if (sess != null) {
				sess.reset(reminder.theUser);
			} else {
				AppContext.setCurrentUserSession(new UserSession(
						reminder.theUser));
			}
			
			Map commonReplaceMap = TitaonMailHelper.getInstance()
					.generateCompanyMacro(companyMgr.getCompany(companyID));
			commonReplaceMap.putAll(TitaonMailHelper.getInstance()
					.generateUserMacro(reminder.theUser));
			/*
			 * send daily timing reminder
			 */
			if(reminder.dtReminder != null){
				long lastSubmit = 0;
				Map dtReminderReplaceMap = (Map) ((HashMap) commonReplaceMap).clone();
				MailData dtData = MailData.defaulMailData();
				dtData.setRecipients(new String[] { reminder.theUser.getUserVO()
						.getEmail() });
				dtData.setReplacementMap(dtReminderReplaceMap);
				if(reminder.dtReminder.getLastSubmit() != null){
					lastSubmit = reminder.dtReminder.getLastSubmit().getTime();
				}
					
				long currentDate = System.currentTimeMillis();
				long nSubmitDays = (currentDate - lastSubmit) / ONE_DAY_IN_MS;
				if(nSubmitDays >= companyMgr.getCompanyConfig(companyID).getDailyTimingReminderInterval()){
					dtReminderReplaceMap.put(TitaonMailHelper.MACRO_N_SUBMIT_DAYS,
							nSubmitDays);
					dtReminderReplaceMap.put(TitaonMailHelper.MACRO_LAST_SUBMIT,
							TitaonMailHelper.reminderDateFormat.format(reminder.dtReminder.getLastSubmit()));
					MailProcessor.getInstance().processMail(
							TitaonMailHelper.MAIL_NAME_REQUIRE_SUBMIT_DAILYTIMIG, dtData,
							TitaonMailHelper.MAIL_NAME_REQUIRE_SUBMIT_DAILYTIMIG,
							AppContext.getLocale());
				}
			}
			/*
			 * approval reminder.
			 */
			if(reminder.appReminders.size() > 0){
				StringBuilder toBeApprovedRecords = new StringBuilder();
				Map appApprovalReplaceMap = (Map) ((HashMap) commonReplaceMap).clone();
				MailData appData = MailData.defaulMailData();
				appData.setRecipients(new String[] { reminder.theUser.getUserVO()
						.getEmail() });
				appData.setReplacementMap(appApprovalReplaceMap);
				for(ApplicationReminder rem : reminder.appReminders){
					toBeApprovedRecords.append("姓名:");
					toBeApprovedRecords.append(rem.applier.getUserVO().getRealName());
					toBeApprovedRecords.append(",批复类型:");
					toBeApprovedRecords.append(I18nSupport.getMessage(rem.reminder.getType()));
					toBeApprovedRecords.append(",提交时间:");
					toBeApprovedRecords.append(TitaonMailHelper.reminderDateFormat.format(rem.reminder.getSubmitDate()));
					toBeApprovedRecords.append("\n");
				}
				appApprovalReplaceMap.put(TitaonMailHelper.MACRO_N_AUUTO_APPROVAL,companyMgr.getCompanyConfig(companyID).getAutoApproveDays());
				appApprovalReplaceMap.put(TitaonMailHelper.MACRO_TO_BE_APPROVED_RECORDS,
						toBeApprovedRecords.toString());
				
				MailProcessor.getInstance().processMail(
						TitaonMailHelper.MAIL_NAME_REQUIRED_APPROVE, appData,
						TitaonMailHelper.MAIL_NAME_REQUIRED_APPROVE,
						AppContext.getLocale());
			}
		} catch (Exception e) {
			logger.error("error while process the user:" + userID, e);
		}
	}

	private static class UserReminder {
		private UserBO theUser;
		private DailyTimingReminder dtReminder;
		private List<ApplicationReminder> appReminders = new ArrayList<ApplicationReminder>();

		private void add(ToBeApproveReminder reminder, UserBO applier) {
			ApplicationReminder appReminder = new ApplicationReminder();
			appReminder.reminder = reminder;
			appReminder.applier = applier;
			appReminders.add(appReminder);
		}
	}

	private static class ApplicationReminder {
		private ToBeApproveReminder reminder;
		private UserBO applier;
	}
}
